package com.sqlcheck.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sqlcheck.dto.request.UnifiedAnalysisRequest;
import com.sqlcheck.entity.ScanTask;
import com.sqlcheck.entity.ScanResult;
import com.sqlcheck.model.SqlStatement;
import com.sqlcheck.repository.ScanResultRepository;
import com.sqlcheck.service.ScanTaskService;
import com.sqlcheck.service.SqlContentExtractionService;
import com.sqlcheck.service.SqlExtractionResult;
import com.sqlcheck.service.UnifiedAnalysisService;
import com.sqlcheck.service.SqlStatementService;
import com.sqlcheck.service.CompatibilityRuleEngine;
import com.sqlcheck.service.TaskProgressService;
import com.sqlcheck.service.ProgressCallback;
import com.sqlcheck.service.AIEnhancementService;
import com.sqlcheck.common.enums.DatabaseType;
import com.sqlcheck.enums.TaskType;
import com.sqlcheck.enums.TaskStatus;
import com.sqlcheck.enums.TaskStage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 统一扫描任务执行器
 * 支持Git源码扫描和数据库DDL扫描，直接集成分层分析逻辑
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UnifiedScanTaskExecutionServiceImpl {

    private final Map<String, SqlContentExtractionService> extractionServices;
    private final ScanTaskService scanTaskService;
    private final ScanResultRepository scanResultRepository;
    private final SqlStatementService sqlStatementService;
    private final CompatibilityRuleEngine ruleEngine;
    private final TaskProgressService taskProgressService;
    private final AIEnhancementService aiEnhancementService;

    /**
     * 执行扫描任务
     */
    public void executeTask(ScanTask task) {
        try {
            log.info("开始执行统一扫描任务: task={}", task);

            // 启动任务进度跟踪
            taskProgressService.startTask(task.getId(), task.getTaskType());

            // 1. 初始化和配置验证
            taskProgressService.updateProgress(task.getId(), TaskStage.INITIALIZATION, 1,
                    "正在初始化任务执行环境...");

            SqlContentExtractionService extractionService = getExtractionService(task.getTaskType());

            taskProgressService.updateProgress(task.getId(), TaskStage.CONFIG_VALIDATION, 4,
                    "验证任务配置和服务依赖...");

            // 2. SQL内容提取阶段 - 根据任务类型使用不同的进度节点
            if (task.getTaskType() == TaskType.GIT_SOURCE_SCAN) {
                executeGitScanSteps(task, extractionService);
            } else if (task.getTaskType() == TaskType.DATABASE_DDL_SCAN) {
                executeDatabaseScanSteps(task, extractionService);
            } else {
                executeManualSqlSteps(task, extractionService);
            }

        } catch (Exception e) {
            log.error("统一扫描任务执行失败: taskId={}", task.getId(), e);
            updateTaskError(task.getId(), e.getMessage());
        }
    }

    /**
     * 执行Git扫描步骤
     */
    private void executeGitScanSteps(ScanTask task, SqlContentExtractionService extractionService) {
        try {
            // Git克隆阶段
            taskProgressService.updateProgress(task.getId(), TaskStage.GIT_CLONE_START, 6,
                    "准备从Git仓库下载代码...");

            taskProgressService.updateProgress(task.getId(), TaskStage.GIT_CLONING, 12,
                    "正在下载代码，请耐心等待...");

            // SQL提取
            taskProgressService.updateProgress(task.getId(), TaskStage.GIT_CLONE_COMPLETE, 18,
                    "代码下载完成，开始扫描源码文件...");

            SqlExtractionResult extractionResult = extractionService.extractSqlContent(task);

            taskProgressService.updateProgress(task.getId(), TaskStage.CODE_SCANNING, 23,
                    "正在扫描Java和XML文件...");

            // 处理提取结果
            processExtractionResult(task, extractionResult);

        } catch (Exception e) {
            throw new RuntimeException("Git扫描执行失败: " + e.getMessage(), e);
        }
    }

    /**
     * 执行数据库扫描步骤
     */
    private void executeDatabaseScanSteps(ScanTask task, SqlContentExtractionService extractionService) {
        try {
            // 数据库连接阶段
            taskProgressService.updateProgress(task.getId(), TaskStage.DB_CONNECTING, 7,
                    "正在连接数据库...");

            taskProgressService.updateProgress(task.getId(), TaskStage.DDL_EXTRACTING, 15,
                    "正在提取DDL语句...");

            SqlExtractionResult extractionResult = extractionService.extractSqlContent(task);

            // 处理提取结果
            processExtractionResult(task, extractionResult);

        } catch (Exception e) {
            throw new RuntimeException("数据库扫描执行失败: " + e.getMessage(), e);
        }
    }

    /**
     * 执行手动SQL步骤
     */
    private void executeManualSqlSteps(ScanTask task, SqlContentExtractionService extractionService) {
        try {
            taskProgressService.updateProgress(task.getId(), TaskStage.SQL_EXTRACTION_START, 26,
                    "开始解析手动输入的SQL语句...");

            SqlExtractionResult extractionResult = extractionService.extractSqlContent(task);

            // 处理提取结果
            processExtractionResult(task, extractionResult);

        } catch (Exception e) {
            throw new RuntimeException("手动SQL分析执行失败: " + e.getMessage(), e);
        }
    }

    /**
     * 处理SQL提取结果（通用流程）
     */
    private void processExtractionResult(ScanTask task, SqlExtractionResult extractionResult) {

        if (!extractionResult.isSuccess()) {
            String errorMsg = extractionResult.getErrorMessage();
            if (errorMsg == null || errorMsg.trim().isEmpty()) {
                errorMsg = "SQL内容提取失败，但未提供详细错误信息";
            }
            throw new RuntimeException(errorMsg);
        }

        List<SqlStatement> sqlStatements = extractionResult.getSqlStatements();
        log.info("任务 {} 提取到 {} 条SQL语句", task.getId(), sqlStatements.size());

        if (sqlStatements.isEmpty()) {
            log.warn("任务 {} 未提取到任何SQL语句", task.getId());
            Map<String, Object> emptyStats = Map.of("sqlCount", 0, "issueCount", 0);
            taskProgressService.completeTask(task.getId(), emptyStats);
            updateTaskStatus(task.getId(), TaskStatus.SUCCESS, 100);
            return;
        }

        // SQL提取完成里程碑
        Map<String, Object> extractionStats = Map.of("sqlCount", sqlStatements.size());
        taskProgressService.updateProgress(task.getId(), TaskStage.SQL_PARSING, 30,
                String.format("成功解析%d条SQL语句", sqlStatements.size()));

        taskProgressService.reportMilestone(task.getId(), TaskStage.SQL_EXTRACTION_COMPLETE,
                extractionStats);

        // 保存SQL语句到数据库
        taskProgressService.updateProgress(task.getId(), TaskStage.SQL_SAVING, 37,
                "正在保存SQL语句到数据库...");
        saveSqlStatements(task, sqlStatements, extractionResult.getMetadata());

        // 重新从数据库加载带有ID的SQL语句
        List<SqlStatement> statementsWithId = loadSqlStatementsWithId(task.getId());

        // 规则分析阶段
        taskProgressService.updateProgress(task.getId(), TaskStage.RULE_ANALYSIS_START, 41,
                "开始兼容性规则分析...");

        List<ScanResult> allResults = analyzeStatementsBatch(statementsWithId, task);

        // 规则分析完成里程碑
        Map<String, Object> ruleStats = Map.of(
                "sqlCount", sqlStatements.size(),
                "issueCount", allResults.size());
        taskProgressService.reportMilestone(task.getId(), TaskStage.RULE_ANALYSIS_COMPLETE, ruleStats);

        // 注意：规则分析结果已经立即保存到数据库中，以便AI验证能够找到它们
        // AI验证会直接更新数据库中的记录，最终这里只需要处理任务完成的统计

        // 任务结果聚合（主要是统计信息更新）
        taskProgressService.updateProgress(task.getId(), TaskStage.RESULT_AGGREGATION, 82,
                "正在聚合分析结果...");

        // 如果有AI增强但allResults为空（被AI过滤），则从数据库获取最终结果用于统计
        if (isAiEnhancementEnabled(task) && allResults.isEmpty()) {
            // 从数据库获取最终结果进行统计
            allResults = scanResultRepository.selectList(
                    new QueryWrapper<ScanResult>().eq("task_id", task.getId()));
            log.info("从数据库获取最终结果用于统计: taskId={}, 问题数={}", task.getId(), allResults.size());
        }

        updateTaskExtractionStats(task, sqlStatements, extractionResult.getMetadata());

        // 任务完成里程碑
        long durationMs = System.currentTimeMillis() -
                task.getCreatedAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        Map<String, Object> finalStats = Map.of(
                "sqlCount", sqlStatements.size(),
                "issueCount", allResults.size(),
                "duration", durationMs);

        updateTaskStatus(task.getId(), TaskStatus.SUCCESS, 100);
        taskProgressService.completeTask(task.getId(), finalStats);

        log.info("统一扫描任务完成: taskId={}, 语句数={}, 问题数={}",
                task.getId(), sqlStatements.size(), allResults.size());
    }

    /**
     * 从数据库加载带有ID的SQL语句模型对象
     */
    private List<com.sqlcheck.model.SqlStatement> loadSqlStatementsWithId(Long taskId) {
        List<com.sqlcheck.entity.SqlStatement> entities = sqlStatementService.getStatementsByTask(taskId);

        return entities.stream().map(entity -> com.sqlcheck.model.SqlStatement.builder()
                .id(entity.getId()) // 设置数据库ID
                .taskId(entity.getTaskId())
                .statementNumber(entity.getStatementNumber())
                .content(entity.getContent())
                .contentHash(entity.getContentHash())
                .sqlType(convertSqlType(entity.getSqlType()))
                .sourceType(convertSourceType(entity.getSourceType()))
                .ddlType(convertDdlType(entity.getDdlType()))
                .sourceFile(entity.getSourceFile())
                .lineNumber(entity.getLineNumber())
                .columnNumber(entity.getColumnNumber())
                .className(entity.getClassName())
                .methodName(entity.getMethodName())
                .javaAnnotationType(convertJavaAnnotationType(entity.getJavaAnnotationType()))
                .mybatisXmlElement(convertMybatisXmlElement(entity.getMybatisXmlElement()))
                .primaryTable(entity.getPrimaryTable())
                .affectedTables(entity.getAffectedTables())
                .databaseObjects(entity.getDatabaseObjects())
                .extractionMetadata(entity.getExtractionMetadata())
                .isNativeQuery(entity.getIsNativeQuery())
                .isDerivedQuery(entity.getIsDerivedQuery())
                .build()).collect(Collectors.toList());
    }

    private com.sqlcheck.model.SqlStatement.SqlType convertSqlType(com.sqlcheck.entity.SqlStatement.SqlType sqlType) {
        if (sqlType == null)
            return null;
        return com.sqlcheck.model.SqlStatement.SqlType.valueOf(sqlType.name());
    }

    private com.sqlcheck.model.SqlStatement.SourceType convertSourceType(
            com.sqlcheck.entity.SqlStatement.SourceType sourceType) {
        if (sourceType == null)
            return null;
        return com.sqlcheck.model.SqlStatement.SourceType.valueOf(sourceType.name());
    }

    private com.sqlcheck.model.SqlStatement.DdlType convertDdlType(com.sqlcheck.entity.SqlStatement.DdlType ddlType) {
        if (ddlType == null)
            return null;
        return com.sqlcheck.model.SqlStatement.DdlType.valueOf(ddlType.name());
    }

    private com.sqlcheck.model.SqlStatement.JavaAnnotationType convertJavaAnnotationType(
            com.sqlcheck.entity.SqlStatement.JavaAnnotationType javaAnnotationType) {
        if (javaAnnotationType == null)
            return null;
        return com.sqlcheck.model.SqlStatement.JavaAnnotationType.valueOf(javaAnnotationType.name());
    }

    private com.sqlcheck.model.SqlStatement.MybatisXmlElement convertMybatisXmlElement(
            com.sqlcheck.entity.SqlStatement.MybatisXmlElement mybatisXmlElement) {
        if (mybatisXmlElement == null)
            return null;
        return com.sqlcheck.model.SqlStatement.MybatisXmlElement.valueOf(mybatisXmlElement.name());
    }

    /**
     * 根据任务类型获取SQL提取服务
     */
    private SqlContentExtractionService getExtractionService(TaskType taskType) {
        String serviceName = getExtractionServiceName(taskType);
        SqlContentExtractionService service = extractionServices.get(serviceName);

        if (service == null) {
            throw new RuntimeException("不支持的任务类型: " + taskType);
        }

        return service;
    }

    private String getExtractionServiceName(TaskType taskType) {
        switch (taskType) {
            case GIT_SOURCE_SCAN:
                return "gitSqlExtractionService";
            case DATABASE_DDL_SCAN:
                return "databaseDdlSqlExtractionService";
            default:
                throw new UnsupportedOperationException("不支持的任务类型: " + taskType);
        }
    }

    /**
     * 逐语句分析（降级方案）
     */
    private List<ScanResult> analyzeStatementsOneByOne(
            List<SqlStatement> sqlStatements, ScanTask task) {

        List<ScanResult> allResults = new ArrayList<>();
        int totalStatements = sqlStatements.size();

        for (int i = 0; i < totalStatements; i++) {
            SqlStatement statement = sqlStatements.get(i);
            int statementNumber = statement.getStatementNumber(); // 已分配的全局编号

            try {
                log.info("分析语句 {}/{} (编号{}): {} | 来源: {}",
                        i + 1, totalStatements, statementNumber,
                        truncateContent(statement.getContent(), 50),
                        statement.getSourceFile());

                // 直接使用规则引擎分析单条语句
                DatabaseType sourceDbType = DatabaseType.valueOf(
                        task.getSourceDbType() != null ? task.getSourceDbType() : "ORACLE");
                DatabaseType targetDbType = DatabaseType.valueOf(
                        task.getTargetDbType() != null ? task.getTargetDbType() : "GOLDENDB");

                List<ScanResult> statementResults = ruleEngine.checkCompatibility(
                        statement, sourceDbType, targetDbType, task.getId());

                allResults.addAll(statementResults);

                // 更新进度
                int progressDelta = (int) (40.0 * (i + 1) / totalStatements);
                updateProgress(task, 40 + progressDelta,
                        String.format("已分析 %d/%d 条语句", i + 1, totalStatements));

            } catch (Exception e) {
                log.error("语句分析失败: statementNumber={}", statementNumber, e);
                ScanResult errorResult = createAnalysisErrorResult(statement, statementNumber, e, task.getId());
                allResults.add(errorResult);
            }
        }

        return allResults;
    }

    /**
     * 使用分层分析方法批量分析SQL语句
     * 第一阶段：规则引擎分析
     * 第二阶段：AI增强验证（如果启用）
     */
    private List<ScanResult> analyzeStatementsBatch(
            List<SqlStatement> sqlStatements, ScanTask task) {

        if (sqlStatements.isEmpty()) {
            return Collections.emptyList();
        }

        try {
            log.info("开始执行分层分析: taskId={}, 语句总数={}, AI增强: {}",
                    task.getId(), sqlStatements.size(), task.getAiEnhancementEnabled());

            // 第一阶段：规则引擎分析 (42-68%)
            taskProgressService.updateProgress(task.getId(), TaskStage.RULE_LOADING, 43,
                    "正在加载兼容性规则...");

            List<ScanResult> ruleResults = performRuleAnalysis(sqlStatements, task);

            log.info("规则分析完成: taskId={}, 发现问题数={}", task.getId(), ruleResults.size());

            // 立即保存规则分析结果到数据库，以便AI验证能够找到它们
            if (!ruleResults.isEmpty()) {
                saveRuleAnalysisResults(task.getId(), ruleResults);
                log.info("规则分析结果已保存到数据库: taskId={}, 问题数={}", task.getId(), ruleResults.size());
            }

            // 第二阶段：AI增强验证（如果启用且有问题需要验证）(70-80%)
            List<ScanResult> finalResults = ruleResults;
            if (isAiEnhancementEnabled(task) && !ruleResults.isEmpty()) {
                taskProgressService.updateProgress(task.getId(), TaskStage.AI_PREPARATION, 71,
                        "准备AI增强验证...");

                finalResults = performAiEnhancementVerification(task, ruleResults);

                // AI验证完成里程碑
                Map<String, Object> aiStats = Map.of(
                        "originalIssueCount", ruleResults.size(),
                        "confirmedCount", finalResults.size());
                taskProgressService.reportMilestone(task.getId(), TaskStage.AI_VERIFICATION_COMPLETE, aiStats);

                log.info("AI增强验证完成: taskId={}, 最终问题数={}", task.getId(), finalResults.size());
            }

            return finalResults;

        } catch (Exception e) {
            log.error("分层分析异常，降级为逐语句分析: taskId={}", task.getId(), e);
            return analyzeStatementsOneByOne(sqlStatements, task);
        }
    }

    /**
     * 判断是否启用AI增强验证
     */
    private boolean isAiEnhancementEnabled(ScanTask task) {
        return task.getAiEnhancementEnabled() != null && task.getAiEnhancementEnabled();
    }

    /**
     * 执行规则分析（第一阶段）- 直接返回ScanResult
     */
    private List<ScanResult> performRuleAnalysis(
            List<SqlStatement> sqlStatements, ScanTask task) {

        List<ScanResult> allResults = new ArrayList<>();
        int totalStatements = sqlStatements.size();

        try {
            // 构建数据库类型
            DatabaseType sourceDbType = DatabaseType.valueOf(
                    task.getSourceDbType() != null ? task.getSourceDbType() : "ORACLE");
            DatabaseType targetDbType = DatabaseType.valueOf(
                    task.getTargetDbType() != null ? task.getTargetDbType() : "GOLDENDB");

            taskProgressService.updateProgress(task.getId(), TaskStage.RULE_MATCHING, 45,
                    String.format("开始匹配%d条SQL语句的兼容性规则...", totalStatements));

            // 批量分析SQL语句
            List<ScanResult> results = ruleEngine.checkCompatibility(sqlStatements, sourceDbType, targetDbType,
                    task.getId());
            allResults.addAll(results);

            // 规则结果处理阶段
            taskProgressService.updateProgress(task.getId(), TaskStage.RULE_RESULT_PROCESSING, 60,
                    String.format("正在处理规则分析结果，共发现%d个兼容性问题", allResults.size()));

            return allResults;

        } catch (Exception e) {
            log.error("规则分析整体失败: taskId={}", task.getId(), e);
            throw new RuntimeException("规则分析失败: " + e.getMessage());
        }
    }

    /**
     * 执行AI增强验证（第二阶段）
     * 使用AIEnhancementService进行真实的AI验证
     */
    private List<ScanResult> performAiEnhancementVerification(
            ScanTask task, List<ScanResult> ruleResults) {

        try {
            // AI验证开始
            taskProgressService.updateProgress(task.getId(), TaskStage.AI_VERIFICATION_START, 75,
                    "开始AI增强验证，正在连接AI服务...");

            if (ruleResults.isEmpty()) {
                log.info("没有规则结果需要AI验证 - 任务ID: {}", task.getId());
                return ruleResults;
            }

            // 创建进度回调
            ProgressCallback aiProgressCallback = taskProgressService.createProgressCallback(
                    task.getId(), TaskStage.AI_BATCH_PROCESSING, "AI增强验证", 75, 5);

            // 调用AIEnhancementService进行真实的AI验证
            List<ScanResult> verifiedResults = aiEnhancementService.verifyRuleResults(
                    task.getId(), ruleResults, aiProgressCallback);

            log.info("AI增强验证完成: taskId={}, 验证结果数={}", task.getId(), verifiedResults.size());
            return verifiedResults;

        } catch (Exception e) {
            log.error("AI增强验证失败: taskId={}, 保留原始规则结果", task.getId(), e);
            return ruleResults; // 验证失败时返回原始规则结果
        }
    }

    /**
     * 创建分析错误的ScanResult
     */
    private ScanResult createAnalysisErrorResult(SqlStatement statement, int statementNumber, Exception error,
            Long taskId) {
        ScanResult result = new ScanResult();
        result.setTaskId(taskId);
        result.setStatementId(statement.getId());
        result.setStatementNumber(statementNumber);
        result.setIssueType(ScanResult.IssueType.SYNTAX_ERROR);
        result.setSeverity(ScanResult.Severity.HIGH);
        result.setRuleId("ANALYSIS_ERROR");
        result.setRuleName("SQL语句分析错误");
        result.setIssueDescription("SQL语句分析失败: " + error.getMessage());
        result.setSuggestion("请检查SQL语法是否正确，或联系管理员");
        result.setSqlContent(statement.getContent());
        result.setFilePath(statement.getSourceFile());
        result.setLineNumber(statement.getLineNumber());
        result.setColumnNumber(statement.getColumnNumber());
        result.setAnalysisEngine("RULE");
        return result;
    }

    /**
     * 构建单句分析请求
     */
    private UnifiedAnalysisRequest buildStatementAnalysisRequest(SqlStatement statement, ScanTask task) {
        // 从任务配置中提取数据库类型信息
        TaskAnalysisConfig analysisConfig = extractAnalysisConfig(task);

        // 根据配置确定是否启用AI增强
        boolean aiEnhancementEnabled = "LLM_BASED".equals(analysisConfig.getAnalysisEngine());

        log.debug("构建分析请求: taskId={}, engine={}, aiEnhanced={}, sourceDb={}, targetDb={}",
                task.getId(), analysisConfig.getAnalysisEngine(), aiEnhancementEnabled,
                analysisConfig.getSourceDbType(), analysisConfig.getTargetDbType());

        return UnifiedAnalysisRequest.builder()
                .sqlContent(statement.getContent())
                .sourceDbType(DatabaseType.valueOf(analysisConfig.getSourceDbType()))
                .targetDbType(DatabaseType.valueOf(analysisConfig.getTargetDbType()))
                .aiEnhancementEnabled(aiEnhancementEnabled)
                .taskName("Task-" + task.getId() + "-Statement-" + statement.getStatementNumber())
                .userId(task.getUserId())
                .build();
    }

    /**
     * 从任务配置中提取分析配置
     */
    private TaskAnalysisConfig extractAnalysisConfig(ScanTask task) {
        try {
            Map<String, Object> config = task.getConfig();
            if (config == null) {
                log.warn("任务配置为空，使用默认分析配置: taskId={}", task.getId());
                return TaskAnalysisConfig.builder()
                        .sourceDbType("MYSQL")
                        .targetDbType("GOLDENDB")
                        .analysisEngine("RULE_BASED")
                        .build();
            }

            String sourceDbType = (String) config.getOrDefault("sourceDbType", "MYSQL");
            String targetDbType = (String) config.getOrDefault("targetDbType", "GOLDENDB");
            String analysisEngine = (String) config.getOrDefault("analysisEngine", "RULE_BASED");

            log.debug("从任务配置提取分析配置: taskId={}, sourceDb={}, targetDb={}, engine={}",
                    task.getId(), sourceDbType, targetDbType, analysisEngine);

            return TaskAnalysisConfig.builder()
                    .sourceDbType(sourceDbType)
                    .targetDbType(targetDbType)
                    .analysisEngine(analysisEngine)
                    .build();
        } catch (Exception e) {
            log.warn("解析任务分析配置失败，使用默认配置: taskId={}, error={}", task.getId(), e.getMessage());
            return TaskAnalysisConfig.builder()
                    .sourceDbType("MYSQL")
                    .targetDbType("GOLDENDB")
                    .analysisEngine("RULE_BASED")
                    .build();
        }
    }

    /**
     * 保存SQL语句到数据库
     */
    private void saveSqlStatements(ScanTask task, List<com.sqlcheck.model.SqlStatement> modelStatements,
            SqlExtractionResult.ExtractionMetadata metadata) {
        try {
            log.info("保存SQL语句到数据库: taskId={}, 语句数={}", task.getId(), modelStatements.size());

            if (modelStatements.isEmpty()) {
                log.info("没有SQL语句需要保存: taskId={}", task.getId());
                return;
            }

            // 清理该任务之前的SQL语句记录，避免重试时的唯一约束冲突
            sqlStatementService.cleanupTaskStatements(task.getId());

            // 转换model.SqlStatement为entity.SqlStatement
            List<com.sqlcheck.entity.SqlStatement> entityStatements = convertToEntityStatements(task.getId(),
                    modelStatements, metadata);

            // 批量保存到数据库
            sqlStatementService.batchSaveStatements(entityStatements);

            log.info("SQL语句保存完成: taskId={}, 保存语句数={}", task.getId(), entityStatements.size());

        } catch (Exception e) {
            log.error("保存SQL语句失败: taskId={}", task.getId(), e);
            throw new RuntimeException("保存SQL语句失败: " + e.getMessage());
        }
    }

    /**
     * 将model.SqlStatement转换为entity.SqlStatement
     */
    private List<com.sqlcheck.entity.SqlStatement> convertToEntityStatements(Long taskId,
            List<com.sqlcheck.model.SqlStatement> modelStatements,
            SqlExtractionResult.ExtractionMetadata metadata) {
        return modelStatements.stream().map(modelStmt -> {
            try {
                // 生成内容哈希
                String contentHash = generateContentHash(modelStmt.getContent());

                // 转换SQL类型
                com.sqlcheck.entity.SqlStatement.SqlType entitySqlType = convertSqlType(modelStmt.getSqlType());
                com.sqlcheck.entity.SqlStatement.SourceType entitySourceType = convertSourceType(
                        modelStmt.getSourceType());
                com.sqlcheck.entity.SqlStatement.DdlType entityDdlType = convertDdlType(modelStmt.getDdlType());

                // 构建entity对象
                return com.sqlcheck.entity.SqlStatement.builder()
                        .taskId(taskId)
                        .statementNumber(modelStmt.getStatementNumber())
                        .content(modelStmt.getContent())
                        .contentHash(contentHash)
                        .sqlType(entitySqlType)
                        .sourceType(entitySourceType)
                        .ddlType(entityDdlType)
                        .sourceFile(modelStmt.getSourceFile())
                        .lineNumber(modelStmt.getLineNumber())
                        .columnNumber(modelStmt.getColumnNumber())
                        .className(modelStmt.getClassName())
                        .methodName(modelStmt.getMethodName())
                        .primaryTable(modelStmt.getPrimaryTable())
                        .isNativeQuery(modelStmt.getIsNativeQuery())
                        .isDerivedQuery(modelStmt.getIsDerivedQuery())
                        .deleted(false)
                        .build();

            } catch (Exception e) {
                log.error("转换SQL语句失败: statementNumber={}, content={}",
                        modelStmt.getStatementNumber(), truncateContent(modelStmt.getContent(), 50), e);
                throw new RuntimeException("转换SQL语句失败: " + e.getMessage());
            }
        }).collect(Collectors.toList());
    }

    /**
     * 生成内容哈希
     */
    private String generateContentHash(String content) {
        if (content == null)
            return null;
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(content.getBytes(java.nio.charset.StandardCharsets.UTF_8));
            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            log.warn("生成内容哈希失败，使用内容长度作为替代: {}", e.getMessage());
            return String.valueOf(content.length());
        }
    }

    /**
     * 转换SQL类型
     */
    private com.sqlcheck.entity.SqlStatement.SqlType convertSqlType(com.sqlcheck.model.SqlStatement.SqlType modelType) {
        if (modelType == null)
            return com.sqlcheck.entity.SqlStatement.SqlType.QUERY;

        switch (modelType) {
            case QUERY:
                return com.sqlcheck.entity.SqlStatement.SqlType.QUERY;
            case DML:
                return com.sqlcheck.entity.SqlStatement.SqlType.DML;
            case DDL:
                return com.sqlcheck.entity.SqlStatement.SqlType.DDL;
            case PROCEDURE:
                return com.sqlcheck.entity.SqlStatement.SqlType.PROCEDURE;
            case FUNCTION:
                return com.sqlcheck.entity.SqlStatement.SqlType.FUNCTION;
            case TRIGGER:
                return com.sqlcheck.entity.SqlStatement.SqlType.TRIGGER;
            default:
                return com.sqlcheck.entity.SqlStatement.SqlType.QUERY;
        }
    }

    /**
     * 转换来源类型
     */
    private com.sqlcheck.entity.SqlStatement.SourceType convertSourceType(
            com.sqlcheck.model.SqlStatement.SourceType modelType) {
        if (modelType == null)
            return com.sqlcheck.entity.SqlStatement.SourceType.MANUAL_INPUT;

        switch (modelType) {
            case MYBATIS_XML:
                return com.sqlcheck.entity.SqlStatement.SourceType.MYBATIS_XML;
            case MYBATIS_ANNOTATION:
                return com.sqlcheck.entity.SqlStatement.SourceType.MYBATIS_ANNOTATION;
            case JPA_ANNOTATION:
                return com.sqlcheck.entity.SqlStatement.SourceType.JPA_ANNOTATION;
            case DDL_SCRIPT:
                return com.sqlcheck.entity.SqlStatement.SourceType.DDL_SCRIPT;
            case MANUAL_INPUT:
                return com.sqlcheck.entity.SqlStatement.SourceType.MANUAL_INPUT;
            default:
                return com.sqlcheck.entity.SqlStatement.SourceType.MANUAL_INPUT;
        }
    }

    /**
     * 转换DDL类型
     */
    private com.sqlcheck.entity.SqlStatement.DdlType convertDdlType(com.sqlcheck.model.SqlStatement.DdlType modelType) {
        if (modelType == null)
            return null;

        switch (modelType) {
            case CREATE_TABLE:
                return com.sqlcheck.entity.SqlStatement.DdlType.CREATE_TABLE;
            case CREATE_INDEX:
                return com.sqlcheck.entity.SqlStatement.DdlType.CREATE_INDEX;
            case CREATE_VIEW:
                return com.sqlcheck.entity.SqlStatement.DdlType.CREATE_VIEW;
            case CREATE_PROCEDURE:
                return com.sqlcheck.entity.SqlStatement.DdlType.CREATE_PROCEDURE;
            case CREATE_FUNCTION:
                return com.sqlcheck.entity.SqlStatement.DdlType.CREATE_FUNCTION;
            case CREATE_TRIGGER:
                return com.sqlcheck.entity.SqlStatement.DdlType.CREATE_TRIGGER;
            case ALTER_TABLE:
                return com.sqlcheck.entity.SqlStatement.DdlType.ALTER_TABLE;
            case DROP_TABLE:
                return com.sqlcheck.entity.SqlStatement.DdlType.DROP_TABLE;
            case DROP_INDEX:
                return com.sqlcheck.entity.SqlStatement.DdlType.DROP_INDEX;
            case OTHER:
                return com.sqlcheck.entity.SqlStatement.DdlType.OTHER;
            default:
                return com.sqlcheck.entity.SqlStatement.DdlType.OTHER;
        }
    }

    /**
     * 保存规则分析结果到数据库
     * 在AI验证之前需要先保存，以便AI验证能够找到并更新这些记录
     */
    private void saveRuleAnalysisResults(Long taskId, List<ScanResult> ruleResults) {
        try {
            log.info("保存规则分析结果: taskId={}, 问题数={}", taskId, ruleResults.size());

            // 清理该任务之前的扫描结果记录，避免重试时的唯一约束冲突
            cleanupTaskScanResults(taskId);

            // 获取任务信息，用于Git URL生成
            ScanTask task = scanTaskService.findById(taskId);
            String repositoryUrl = null;
            String branch = null;

            // 如果是Git扫描任务，从配置中提取Git信息
            if (task != null && task.getTaskType() == TaskType.GIT_SOURCE_SCAN) {
                Map<String, Object> config = task.getConfig();
                if (config != null) {
                    repositoryUrl = (String) config.get("repositoryUrl");
                    branch = (String) config.get("branchName");
                    log.debug("Git任务信息: repositoryUrl={}, branch={}", repositoryUrl, branch);
                }
            }

            // 保存规则分析结果
            for (ScanResult result : ruleResults) {
                // 确保analysis_engine设置为RULE
                result.setAnalysisEngine("RULE");

                // 为Git任务生成gitFileUrl并添加到metadata
                if (task != null && task.getTaskType() == TaskType.GIT_SOURCE_SCAN && repositoryUrl != null) {
                    Map<String, Object> resultMetadata = result.getMetadata() != null
                            ? new HashMap<>(result.getMetadata())
                            : new HashMap<>();

                    String gitFileUrl = buildGitFileUrl(repositoryUrl, branch, result.getFilePath(),
                            result.getLineNumber());
                    if (gitFileUrl != null) {
                        resultMetadata.put("repositoryUrl", repositoryUrl);
                        resultMetadata.put("branch", branch != null ? branch : "master");
                        resultMetadata.put("gitFileUrl", gitFileUrl);
                        result.setMetadata(resultMetadata);
                        log.debug("为Git任务生成gitFileUrl: {}", gitFileUrl);
                    }
                }

                scanResultRepository.insert(result);
            }

            log.info("规则分析结果保存完成: taskId={}, 保存问题数={}", taskId, ruleResults.size());

        } catch (Exception e) {
            log.error("保存规则分析结果失败: taskId={}", taskId, e);
            throw new RuntimeException("保存规则分析结果失败: " + e.getMessage());
        }
    }

    /**
     * 清理指定任务的扫描结果记录（软删除）
     * 用于任务重试时避免数据冲突
     */
    private void cleanupTaskScanResults(Long taskId) {
        try {
            int deletedCount = scanResultRepository.softDeleteByTaskId(taskId);
            log.info("清理任务扫描结果记录: taskId={}, 删除记录数={}", taskId, deletedCount);
        } catch (Exception e) {
            log.error("清理任务扫描结果记录失败: taskId={}", taskId, e);
            // 这里不抛出异常，因为清理失败不应该阻止主流程
            log.warn("忽略扫描结果清理失败，继续执行任务: taskId={}", taskId);
        }
    }

    /**
     * 更新任务进度
     */
    private void updateProgress(ScanTask task, int progress, String message) {
        try {
            scanTaskService.updateTaskStatus(task.getId(), TaskStatus.RUNNING, progress);
            log.info("任务进度更新: taskId={}, progress={}%, message={}", task.getId(), progress, message);
        } catch (Exception e) {
            log.warn("更新任务进度失败: taskId={}, progress={}", task.getId(), progress, e);
        }
    }

    /**
     * 更新任务状态
     */
    private void updateTaskStatus(Long taskId, TaskStatus status, int progress) {
        try {
            scanTaskService.updateTaskStatus(taskId, status, progress);
        } catch (Exception e) {
            log.error("更新任务状态失败: taskId={}, status={}", taskId, status, e);
        }
    }

    /**
     * 更新任务错误信息
     */
    private void updateTaskError(Long taskId, String errorMessage) {
        try {
            scanTaskService.updateTaskError(taskId, errorMessage);
        } catch (Exception e) {
            log.error("更新任务错误信息失败: taskId={}", taskId, e);
        }
    }

    /**
     * 截断内容用于日志显示
     */
    private String truncateContent(String content, int maxLength) {
        if (content == null)
            return null;
        if (content.length() <= maxLength)
            return content;
        return content.substring(0, maxLength) + "...";
    }

    /**
     * 任务分析配置
     */
    private static class TaskAnalysisConfig {
        private String sourceDbType;
        private String targetDbType;
        private String analysisEngine;

        public static TaskAnalysisConfigBuilder builder() {
            return new TaskAnalysisConfigBuilder();
        }

        public String getSourceDbType() {
            return sourceDbType;
        }

        public String getTargetDbType() {
            return targetDbType;
        }

        public String getAnalysisEngine() {
            return analysisEngine;
        }

        public static class TaskAnalysisConfigBuilder {
            private String sourceDbType;
            private String targetDbType;
            private String analysisEngine;

            public TaskAnalysisConfigBuilder sourceDbType(String sourceDbType) {
                this.sourceDbType = sourceDbType;
                return this;
            }

            public TaskAnalysisConfigBuilder targetDbType(String targetDbType) {
                this.targetDbType = targetDbType;
                return this;
            }

            public TaskAnalysisConfigBuilder analysisEngine(String analysisEngine) {
                this.analysisEngine = analysisEngine;
                return this;
            }

            public TaskAnalysisConfig build() {
                TaskAnalysisConfig config = new TaskAnalysisConfig();
                config.sourceDbType = this.sourceDbType;
                config.targetDbType = this.targetDbType;
                config.analysisEngine = this.analysisEngine;
                return config;
            }
        }
    }

    /**
     * 更新任务提取统计信息
     */
    private void updateTaskExtractionStats(ScanTask task, List<com.sqlcheck.model.SqlStatement> sqlStatements,
            SqlExtractionResult.ExtractionMetadata metadata) {
        try {
            log.info("更新任务统计信息: taskId={}, 语句数={}", task.getId(), sqlStatements.size());

            Map<String, Object> extractionStats = generateExtractionStats(task, sqlStatements, metadata);

            // 更新任务的统计信息
            scanTaskService.updateTaskExtractionStats(task.getId(), extractionStats);

            log.info("任务统计信息更新完成: taskId={}", task.getId());

        } catch (Exception e) {
            log.error("更新任务统计信息失败: taskId={}", task.getId(), e);
            // 不抛出异常，避免影响任务完成
        }
    }

    /**
     * 生成提取统计信息
     */
    private Map<String, Object> generateExtractionStats(ScanTask task,
            List<com.sqlcheck.model.SqlStatement> sqlStatements,
            SqlExtractionResult.ExtractionMetadata metadata) {
        Map<String, Object> stats = new HashMap<>();

        // 基本统计
        stats.put("totalStatements", sqlStatements.size());
        stats.put("totalFiles", metadata != null ? countTotalFiles(sqlStatements) : 0);
        stats.put("extractionTimeMs", metadata != null ? metadata.getExtractionTimeMs() : 0);

        // 按SQL类型统计
        Map<String, Long> sqlTypeStats = sqlStatements.stream()
                .collect(Collectors.groupingBy(
                        stmt -> stmt.getSqlType() != null ? stmt.getSqlType().name() : "UNKNOWN",
                        Collectors.counting()));
        stats.put("sqlTypeBreakdown", sqlTypeStats);

        // 按来源类型统计
        Map<String, Long> sourceTypeStats = sqlStatements.stream()
                .collect(Collectors.groupingBy(
                        stmt -> stmt.getSourceType() != null ? stmt.getSourceType().name() : "UNKNOWN",
                        Collectors.counting()));
        stats.put("sourceTypeBreakdown", sourceTypeStats);

        // 根据任务类型添加特定统计信息
        switch (task.getTaskType()) {
            case GIT_SOURCE_SCAN:
                addGitScanStats(stats, sqlStatements, metadata);
                break;
            case DATABASE_DDL_SCAN:
                addDatabaseScanStats(stats, sqlStatements, metadata);
                break;
            default:
                break;
        }

        // 文件统计（如果可用）
        if (metadata != null && metadata.getSourceTypeCounts() != null) {
            stats.put("fileTypeStats", metadata.getSourceTypeCounts());
        }

        return stats;
    }

    /**
     * 添加Git扫描特定统计
     */
    private void addGitScanStats(Map<String, Object> stats, List<com.sqlcheck.model.SqlStatement> sqlStatements,
            SqlExtractionResult.ExtractionMetadata metadata) {
        // 源码文件统计
        long javaFiles = sqlStatements.stream()
                .filter(stmt -> stmt.getSourceFile() != null && stmt.getSourceFile().endsWith(".java"))
                .map(com.sqlcheck.model.SqlStatement::getSourceFile)
                .distinct()
                .count();

        long xmlFiles = sqlStatements.stream()
                .filter(stmt -> stmt.getSourceFile() != null && stmt.getSourceFile().endsWith(".xml"))
                .map(com.sqlcheck.model.SqlStatement::getSourceFile)
                .distinct()
                .count();

        long sqlFiles = sqlStatements.stream()
                .filter(stmt -> stmt.getSourceFile() != null && stmt.getSourceFile().endsWith(".sql"))
                .map(com.sqlcheck.model.SqlStatement::getSourceFile)
                .distinct()
                .count();

        stats.put("javaFiles", javaFiles);
        stats.put("xmlFiles", xmlFiles);
        stats.put("sqlFiles", sqlFiles);
        stats.put("scannedFiles", javaFiles + xmlFiles + sqlFiles);

        // MyBatis和JPA统计
        long mybatisXmlCount = sqlStatements.stream()
                .filter(stmt -> stmt.getSourceType() == com.sqlcheck.model.SqlStatement.SourceType.MYBATIS_XML)
                .count();

        long mybatisAnnotationCount = sqlStatements.stream()
                .filter(stmt -> stmt.getSourceType() == com.sqlcheck.model.SqlStatement.SourceType.MYBATIS_ANNOTATION)
                .count();

        long jpaAnnotationCount = sqlStatements.stream()
                .filter(stmt -> stmt.getSourceType() == com.sqlcheck.model.SqlStatement.SourceType.JPA_ANNOTATION)
                .count();

        stats.put("mybatisXmlStatements", mybatisXmlCount);
        stats.put("mybatisAnnotationStatements", mybatisAnnotationCount);
        stats.put("jpaAnnotationStatements", jpaAnnotationCount);
        stats.put("rulesMatched", mybatisXmlCount + mybatisAnnotationCount + jpaAnnotationCount); // 匹配的规则数
    }

    /**
     * 添加数据库扫描特定统计
     */
    private void addDatabaseScanStats(Map<String, Object> stats, List<com.sqlcheck.model.SqlStatement> sqlStatements,
            SqlExtractionResult.ExtractionMetadata metadata) {
        // DDL类型统计
        long createStatements = sqlStatements.stream()
                .filter(stmt -> stmt.getDdlType() != null &&
                        stmt.getDdlType().name().startsWith("CREATE"))
                .count();

        long alterStatements = sqlStatements.stream()
                .filter(stmt -> stmt.getDdlType() != null &&
                        stmt.getDdlType() == com.sqlcheck.model.SqlStatement.DdlType.ALTER_TABLE)
                .count();

        long dropStatements = sqlStatements.stream()
                .filter(stmt -> stmt.getDdlType() != null &&
                        stmt.getDdlType().name().startsWith("DROP"))
                .count();

        stats.put("createStatements", createStatements);
        stats.put("alterStatements", alterStatements);
        stats.put("dropStatements", dropStatements);

        // 数据库对象统计
        Set<String> tables = sqlStatements.stream()
                .filter(stmt -> stmt.getPrimaryTable() != null)
                .map(com.sqlcheck.model.SqlStatement::getPrimaryTable)
                .collect(Collectors.toSet());

        long tableCount = sqlStatements.stream()
                .filter(stmt -> stmt.getDdlType() != null &&
                        stmt.getDdlType() == com.sqlcheck.model.SqlStatement.DdlType.CREATE_TABLE)
                .count();

        long indexCount = sqlStatements.stream()
                .filter(stmt -> stmt.getDdlType() != null &&
                        stmt.getDdlType() == com.sqlcheck.model.SqlStatement.DdlType.CREATE_INDEX)
                .count();

        long viewCount = sqlStatements.stream()
                .filter(stmt -> stmt.getDdlType() != null &&
                        stmt.getDdlType() == com.sqlcheck.model.SqlStatement.DdlType.CREATE_VIEW)
                .count();

        long procedureCount = sqlStatements.stream()
                .filter(stmt -> stmt.getDdlType() != null &&
                        stmt.getDdlType() == com.sqlcheck.model.SqlStatement.DdlType.CREATE_PROCEDURE)
                .count();

        // 添加数据库对象统计
        Map<String, Object> objectCounts = new HashMap<>();
        objectCounts.put("tables", tableCount);
        objectCounts.put("indexes", indexCount);
        objectCounts.put("views", viewCount);
        objectCounts.put("procedures", procedureCount);
        stats.put("objectCounts", objectCounts);

        // 计算总内容大小
        long totalContentSize = sqlStatements.stream()
                .filter(stmt -> stmt.getContent() != null)
                .mapToLong(stmt -> stmt.getContent().length())
                .sum();
        stats.put("totalContentSize", totalContentSize);
    }

    /**
     * 计算总文件数
     */
    private int countTotalFiles(List<com.sqlcheck.model.SqlStatement> sqlStatements) {
        return (int) sqlStatements.stream()
                .filter(stmt -> stmt.getSourceFile() != null)
                .map(com.sqlcheck.model.SqlStatement::getSourceFile)
                .distinct()
                .count();
    }

    /**
     * 构建Git文件跳转URL
     */
    private String buildGitFileUrl(String repositoryUrl, String branch, String filePath, Integer lineNumber) {
        if (repositoryUrl == null || filePath == null) {
            return null;
        }

        try {
            // 标准化仓库URL，统一为Web可访问的base URL
            String baseUrl = normalizeRepositoryUrl(repositoryUrl);

            // 规范化路径，去掉前导./ 并统一为正斜杠
            // 同时移除任务前缀路径（如"task-136/"）
            String normalizedPath = filePath
                    .replace('\\', '/')
                    .replaceAll("^\\./+", "")
                    .replaceAll("^task-\\d+/", ""); // 移除任务前缀

            // 根据不同平台构建跳转URL
            if (baseUrl.contains("gitlab")) {
                // GitLab: https://gitlab.com/user/repo/-/blob/branch/file#L123
                return String.format("%s/-/blob/%s/%s%s",
                        baseUrl, branch != null ? branch : "main", normalizedPath,
                        lineNumber != null ? "#L" + lineNumber : "");
            } else if (baseUrl.contains("gitee")) {
                // Gitee: https://gitee.com/user/repo/blob/branch/file#L123
                return String.format("%s/blob/%s/%s%s",
                        baseUrl, branch != null ? branch : "master", normalizedPath,
                        lineNumber != null ? "#L" + lineNumber : "");
            } else if (baseUrl.contains("github")) {
                // GitHub: https://github.com/user/repo/blob/branch/file#L123
                return String.format("%s/blob/%s/%s%s",
                        baseUrl, branch != null ? branch : "main", normalizedPath,
                        lineNumber != null ? "#L" + lineNumber : "");
            }

            return baseUrl; // 无法识别平台时返回基础URL

        } catch (Exception e) {
            log.warn("构建Git文件URL失败: {} - {}", repositoryUrl, e.getMessage());
            return repositoryUrl;
        }
    }

    /**
     * 将可能的SSH/带凭证的URL标准化为浏览器可访问的Web URL
     */
    private String normalizeRepositoryUrl(String repoUrl) {
        if (repoUrl == null) {
            return null;
        }

        String url = repoUrl.trim();
        // 去除.git 后缀
        url = url.replaceAll("\\.git$", "");

        // SSH形式: git@host:namespace/repo 或 ssh://git@host/namespace/repo
        if (url.startsWith("git@")) {
            // git@host:namespace/repo -> https://host/namespace/repo
            int at = url.indexOf('@');
            int colon = url.indexOf(':', at + 1);
            if (colon > 0) {
                String host = url.substring(at + 1, colon);
                String path = url.substring(colon + 1);
                return "https://" + host + "/" + path;
            }
        }
        if (url.startsWith("ssh://")) {
            // ssh://git@host/namespace/repo -> https://host/namespace/repo
            String withoutScheme = url.substring("ssh://".length());
            int at = withoutScheme.indexOf('@');
            String hostAndPath = at >= 0 ? withoutScheme.substring(at + 1) : withoutScheme;
            int slash = hostAndPath.indexOf('/');
            if (slash > 0) {
                String host = hostAndPath.substring(0, slash);
                String path = hostAndPath.substring(slash + 1);
                return "https://" + host + "/" + path;
            }
        }

        // http/https 带凭证: https://user:token@host/namespace/repo ->
        // https://host/namespace/repo
        if (url.startsWith("http://") || url.startsWith("https://")) {
            return url.replaceFirst("^https?://[^@]+@", "https://");
        }

        return url;
    }

}